package com.square.service.common.utils;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.IdUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.extension.api.R;
import io.jsonwebtoken.*;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;

/**
 * @author : 王苏
 * @date : 2020/5/26 16:16
 * @description :Jwt工具类
 */
public class JwtUtils {
    // Jwt主题名
    private static final String JWT_SUBJECT = "loginAuth";
    // Jwt参数变量名称-用户名
    public static final String JWT_CLAIM_USERNAME = "username";
    // Jwt签发者
    private static final String JWT_ISSUER = "Auth_Developer";
    // Jwt过期时间（redis）30分钟
    public static final Long JWT_EXPIRE_TIME = 1800L;

    /**
     * 签发JWT
     * 去除setExpiration，设置为永不过期
     *
     * @param username 用户名
     * @param password 用户密码（用作签名）
     * @return
     */
    public static String createJwt(String username, String password) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        Date now = new Date();
        SecretKey secretKey = generalKey(password);
        JwtBuilder builder = Jwts.builder().setId(IdUtil.fastSimpleUUID())
                // 主题
                .setSubject(JWT_SUBJECT)
                // 参数
                .claim(JWT_CLAIM_USERNAME, username)
                // 签发者
                .setIssuer(JWT_ISSUER)
                // 签发时间
                .setIssuedAt(now)
                // 签名算法以及密匙
                .signWith(signatureAlgorithm, secretKey);
        return builder.compact();
    }

    /**
     * 验证JWT
     *
     * @param jwtStr
     * @param password
     * @return
     */
    public static R<Claims> validateJwt(String jwtStr, String password) {
        Claims claims;
        try {
            claims = parseJwt(jwtStr, password);
            return R.ok(claims);
        } catch (ExpiredJwtException e) {
            return R.failed("令牌已过期");
        } catch (SignatureException e) {
            return R.failed("令牌签名异常");
        } catch (Exception e) {
            return R.failed("未知异常");
        }
    }

    /**
     * 生成密匙
     *
     * @param password 用户密码
     * @return
     */
    private static SecretKey generalKey(String password) {
        byte[] encodedKey = Base64.decode(password);
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }

    /**
     * 解析Jwt字符串
     *
     * @param jwt
     * @param password
     * @return
     */
    private static Claims parseJwt(String jwt, String password) {
        SecretKey secretKey = generalKey(password);
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token
     * @param key
     * @return
     */
    public static String getTokenInfo(String token, String key) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(key).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }
}
